package info.u250.c2d.box2deditor.io;

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.JointDef.JointType;
import com.badlogic.gdx.utils.XmlWriter;
import info.u250.c2d.box2d.model.b2BodyDefModel;
import info.u250.c2d.box2d.model.b2FixtureDefModel;
import info.u250.c2d.box2d.model.b2JointDefModel;
import info.u250.c2d.box2d.model.fixture.b2CircleFixtureDefModel;
import info.u250.c2d.box2d.model.fixture.b2PolygonFixtureDefModel;
import info.u250.c2d.box2d.model.fixture.b2RectangleFixtureDefModel;
import info.u250.c2d.box2d.model.joint.*;
import info.u250.c2d.box2deditor.adapter.SceneModelAdapter;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.ObjectInputStream;

public class Export {

    public static void main(String[] args) throws Exception {
        new LwjglApplication(new ApplicationListener() {

            @Override
            public void resume() {
                // TODO Auto-generated method stub

            }

            @Override
            public void resize(int width, int height) {
                // TODO Auto-generated method stub

            }

            @Override
            public void render() {
                // TODO Auto-generated method stub

            }

            @Override
            public void pause() {
                // TODO Auto-generated method stub

            }

            @Override
            public void dispose() {
                // TODO Auto-generated method stub

            }

            String vector2ToStr(Vector2 vector2) {
                return "{" + vector2.x + "," + vector2.y + "}";
            }

            @Override
            public void create() {
                try {
                    File root = new File("assets/examples");
                    for (File f : root.listFiles()) {
                        try {
                            ObjectInputStream in = new ObjectInputStream(new FileInputStream(f));
                            SceneModelAdapter scene = (SceneModelAdapter) in.readObject();
                            in.close();
                            try {
                                XmlWriter xml = new XmlWriter(new FileWriter(new File(f.getAbsolutePath() + ".xml")));
                                xml.element("world");

                                xml.element("fixtures");
                                for (b2FixtureDefModel fixture : scene.fixtureDefModels) {
                                    if (fixture instanceof b2CircleFixtureDefModel) {
                                        xml.element("circle");
                                    } else if (fixture instanceof b2RectangleFixtureDefModel) {
                                        xml.element("box");
                                    } else if (fixture instanceof b2PolygonFixtureDefModel) {
                                        xml.element("polygons");
                                    }
                                    xml.attribute("friction", fixture.friction)
                                            .attribute("restitution", fixture.restitution)
                                            .attribute("density", fixture.density)
                                            .attribute("isSensor", fixture.isSensor)
                                            .attribute("categoryBits", fixture.categoryBits)
                                            .attribute("maskBits", fixture.maskBits)
                                            .attribute("groupIndex", fixture.groupIndex)
                                            .attribute("name", fixture.name)
                                            .attribute("mark", fixture.mark);
                                    if (fixture instanceof b2CircleFixtureDefModel) {
                                        xml.attribute("radius", b2CircleFixtureDefModel.class.cast(fixture).radius);
                                    } else if (fixture instanceof b2RectangleFixtureDefModel) {
                                        xml.attribute("width", b2RectangleFixtureDefModel.class.cast(fixture).width);
                                        xml.attribute("height", b2RectangleFixtureDefModel.class.cast(fixture).height);
                                    } else if (fixture instanceof b2PolygonFixtureDefModel) {
                                        b2PolygonFixtureDefModel polygonFixture = b2PolygonFixtureDefModel.class.cast(fixture);
                                        for (Vector2[] polygon : polygonFixture.vertices) {
                                            xml.element("polygon");
                                            for (Vector2 vertex : polygon) {
                                                xml.element("vertex", vector2ToStr(vertex));
                                            }
                                            xml.pop();
                                        }
                                    }
                                    xml.pop();
                                }
                                xml.pop();

                                xml.element("bodys");
                                for (b2BodyDefModel body : scene.bodyDefModels) {
                                    xml.element("body")
                                            .attribute("name", body.name)
                                            .attribute("type", body.type == 0 ? "StaticBody" : (body.type == 1 ? "KinematicBody" : "DynamicBody"))
                                            .attribute("position", vector2ToStr(body.position))
                                            .attribute("degrees", body.degrees)
                                            .attribute("linearVelocity", vector2ToStr(body.linearVelocity))
                                            .attribute("angularVelocity", body.angularVelocity)
                                            .attribute("linearDamping", body.linearDamping)
                                            .attribute("angularDamping", body.angularDamping)
                                            .attribute("allowSleep", body.allowSleep)
                                            .attribute("awake", body.awake)
                                            .attribute("fixedRotation", body.fixedRotation)
                                            .attribute("bullet", body.bullet)
                                            .attribute("active", body.active)
                                            .attribute("gravityScale", body.gravityScale)
                                            .attribute("drawableOffsetX", body.drawableOffsetX)
                                            .attribute("drawableOffsetY", body.drawableOffsetY)
                                            .attribute("drawableWidth", body.drawableWidth)
                                            .attribute("drawableHeight", body.drawableHeight)
                                            .attribute("mark", body.mark);
                                    for (b2FixtureDefModel fixture : body.fixtures) {
                                        xml.element("fixture").attribute("ref", fixture.name).pop();
                                    }
                                    xml.pop();
                                }
                                xml.pop();
                                xml.element("joints");
                                for (b2JointDefModel b2Joint : scene.jointDefModels) {
                                    xml.element("joint");
                                    xml.attribute("collideConnected", b2Joint.collideConnected);
                                    xml.attribute("bodyA", b2Joint.bodyA.name);
                                    xml.attribute("bodyB", b2Joint.bodyB.name);
                                    xml.attribute("name", b2Joint.name);
                                    xml.attribute("mark", b2Joint.mark);
                                    if (b2Joint instanceof b2DistanceJointDefModel) {
                                        b2DistanceJointDefModel b2Def = b2DistanceJointDefModel.class.cast(b2Joint);
                                        xml.attribute("type", JointType.DistanceJoint)
                                                .attribute("length", b2Def.length)
                                                .attribute("localAnchorA", vector2ToStr(b2Def.localAnchorA))
                                                .attribute("localAnchorB", vector2ToStr(b2Def.localAnchorB))
                                                .attribute("frequencyHz", b2Def.frequencyHz)
                                                .attribute("dampingRatio", b2Def.dampingRatio);
                                    } else if (b2Joint instanceof b2FrictionJointDefModel) {
                                        b2FrictionJointDefModel b2Def = b2FrictionJointDefModel.class.cast(b2Joint);
                                        xml.attribute("type", JointType.FrictionJoint)
                                                .attribute("localAnchorA", vector2ToStr(b2Def.localAnchorA))
                                                .attribute("localAnchorB", vector2ToStr(b2Def.localAnchorB))
                                                .attribute("maxForce", b2Def.maxForce)
                                                .attribute("maxTorque", b2Def.maxTorque);
                                    } else if (b2Joint instanceof b2PrismaticJointDefModel) {
                                        b2PrismaticJointDefModel b2Def = b2PrismaticJointDefModel.class.cast(b2Joint);
                                        xml.attribute("type", JointType.PrismaticJoint)
                                                .attribute("localAxisA", vector2ToStr(b2Def.localAxisA))
                                                .attribute("localAnchorA", vector2ToStr(b2Def.localAnchorA))
                                                .attribute("localAnchorB", vector2ToStr(b2Def.localAnchorB))
                                                .attribute("referenceDegrees", b2Def.referenceDegrees)
                                                .attribute("enableLimit", b2Def.enableLimit)
                                                .attribute("lowerTranslation", b2Def.lowerTranslation)
                                                .attribute("upperTranslation", b2Def.upperTranslation)
                                                .attribute("enableMotor", b2Def.enableMotor)
                                                .attribute("maxMotorForce", b2Def.maxMotorForce)
                                                .attribute("motorSpeed", b2Def.motorSpeed);
                                    } else if (b2Joint instanceof b2RevoluteJointDefModel) {
                                        b2RevoluteJointDefModel b2Def = b2RevoluteJointDefModel.class.cast(b2Joint);
                                        xml.attribute("type", JointType.RevoluteJoint)
                                                .attribute("localAnchorA", vector2ToStr(b2Def.localAnchorA))
                                                .attribute("localAnchorB", vector2ToStr(b2Def.localAnchorB))
                                                .attribute("referenceDegrees", b2Def.referenceDegrees)
                                                .attribute("enableLimit", b2Def.enableLimit)
                                                .attribute("enableMotor", b2Def.enableMotor)
                                                .attribute("maxMotorTorque", b2Def.maxMotorTorque)
                                                .attribute("enableMotor", b2Def.enableMotor)
                                                .attribute("motorSpeed", b2Def.motorSpeed)
                                                .attribute("lowerDegrees", b2Def.lowerDegrees)
                                                .attribute("upperDegrees", b2Def.upperDegrees);
                                    } else if (b2Joint instanceof b2RopeJointDefModel) {
                                        b2RopeJointDefModel b2Def = b2RopeJointDefModel.class.cast(b2Joint);
                                        xml.attribute("type", JointType.RopeJoint)
                                                .attribute("localAnchorA", vector2ToStr(b2Def.localAnchorA))
                                                .attribute("localAnchorB", vector2ToStr(b2Def.localAnchorB))
                                                .attribute("maxLength", b2Def.maxLength);
                                    } else if (b2Joint instanceof b2WeldJointDefModel) {
                                        b2WeldJointDefModel b2Def = b2WeldJointDefModel.class.cast(b2Joint);
                                        xml.attribute("type", JointType.WeldJoint)
                                                .attribute("localAnchorA", vector2ToStr(b2Def.localAnchorA))
                                                .attribute("localAnchorB", vector2ToStr(b2Def.localAnchorB))
                                                .attribute("referenceDegrees", b2Def.referenceDegrees);
                                    } else if (b2Joint instanceof b2WheelJointDefModel) {
                                        b2WheelJointDefModel b2Def = b2WheelJointDefModel.class.cast(b2Joint);
                                        xml.attribute("type", JointType.WheelJoint)
                                                .attribute("localAxisA", vector2ToStr(b2Def.localAxisA))
                                                .attribute("localAnchorA", vector2ToStr(b2Def.localAnchorA))
                                                .attribute("localAnchorB", vector2ToStr(b2Def.localAnchorB))
                                                .attribute("enableMotor", b2Def.enableMotor)
                                                .attribute("maxMotorTorque", b2Def.maxMotorTorque)
                                                .attribute("motorSpeed", b2Def.motorSpeed)
                                                .attribute("frequencyHz", b2Def.frequencyHz)
                                                .attribute("dampingRatio", b2Def.dampingRatio);
                                    } else if (b2Joint instanceof b2PulleyJointDefModel) {
                                        b2PulleyJointDefModel b2Def = b2PulleyJointDefModel.class.cast(b2Joint);
                                        xml.attribute("type", JointType.PulleyJoint)
                                                .attribute("groundAnchorA", vector2ToStr(b2Def.groundAnchorA))
                                                .attribute("groundAnchorB", vector2ToStr(b2Def.groundAnchorB))
                                                .attribute("localAnchorA", vector2ToStr(b2Def.localAnchorA))
                                                .attribute("localAnchorB", vector2ToStr(b2Def.localAnchorB))
                                                .attribute("lengthA", b2Def.lengthA)
                                                .attribute("lengthB", b2Def.lengthB)
                                                .attribute("ratio", b2Def.ratio);
                                    } else if (b2Joint instanceof b2GearJointDefModel) {
                                        //TODO
                                    }
                                    xml.pop();
                                }
                                xml.pop();
                                xml.pop();
                                xml.flush();
                                xml.close();
                            } catch (Exception ex) {
                                ex.printStackTrace();
                            }
                        } catch (Exception e) {
                            System.out.println(f);
                        }
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

}
